package org.db;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.SortedSet;
import java.util.TreeSet;

import javax.xml.XMLConstants;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.TransformerFactoryConfigurationError;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import javax.xml.validation.Validator;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;

import org.db.dao.BauwerkslinienDAO;
import org.db.dao.DAO;
import org.db.dao.GleisDAO;
import org.db.dao.HoehenlinienDAO;
import org.db.dao.KruemmungslinienDAO;
import org.db.dao.LageskizzenGVPDAO;
import org.db.dao.LageskizzenWeichenDAO;
import org.db.dao.ProjektDatenDAO;
import org.db.dao.Uebergangsbogen;
import org.db.dao.UeberhoehungslinienDAO;
import org.db.dao.Ueberhoehungsrampe;
import org.db.dao.change.AddProjektElement;
import org.db.dao.change.ProjektChange;
import org.db.dao.change.RemoveProjektElement;
import org.db.dao.change.UpdateProjektElement;
import org.db.dao.query.QueryResult;
import org.db.util.XMLTags;
import org.w3c.dom.Attr;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

public class Manager {

	private static Manager instance = null;

	private String dataFolder = "data";

	private static final String SCHEMA_FILE = "schema.xsd";

	private String loadedFilePath;

	private Document doc;

	private Element projektNode;

	private Element lageskizzenNode;

	private Element bauwerkslinienNode;

	private Element gleisNode;

	private ProjektDatenDAO projekt;

	private List<GleisDAO> gleisElemente;

	private SortedSet<BauwerkslinienDAO> bauwerkslinienElemente;

	private SortedSet<LageskizzenGVPDAO> lageskizzenGVPs;

	private SortedSet<LageskizzenWeichenDAO> lageskizzenWeichen;

	private List<ProjektChange> scheduledChanges;

	private GleisDAO currentGleis;

	private Manager() {
		dataFolder = ClassLoader.getSystemResource(".").getPath() + "data";
		new File(dataFolder).mkdir();
		reset();
	}

	public synchronized static Manager getInstance() {
		if (instance == null) {
			instance = new Manager();
		}
		return instance;
	}

	private void write2Disk() {
		try {
			TransformerFactory tFactory = TransformerFactory.newInstance();
			Transformer transformer = tFactory.newTransformer();
			transformer.setOutputProperty(OutputKeys.INDENT, "yes"); // pretty
			// print
			transformer.setOutputProperty(
					"{http://xml.apache.org/xslt}indent-amount", "4");
			DOMSource source = new DOMSource(buildDocument());
			StreamResult result = new StreamResult(new BufferedOutputStream(
					new FileOutputStream(createFilePath())));
			transformer.transform(source, result);
			// result = new StreamResult(System.out);
			// transformer.transform(source, result);
		} catch (TransformerConfigurationException e) {
			e.printStackTrace();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (TransformerFactoryConfigurationError e) {
			e.printStackTrace();
		} catch (TransformerException e) {
			e.printStackTrace();
		}
	}

	private String createFilePath() {
		return dataFolder + File.separator + projekt.getAuftragsNr() + ".xml";
	}

	public QueryResult query(double position) {
		BauwerkslinienDAO nearestBauwerkslinienElement = getNearestBauwerkslinienElement(position);
		HoehenlinienDAO nearestHoehenlinienElement = getNearestHoehenlinienElement(position);
		KruemmungslinienDAO nearestKruemmungslinienElement = getNearestKruemmungslinienElement(position);
		UeberhoehungslinienDAO nearestUeberhoehungslinienElement = getNearestUeberhoehungslinienElement(position);
		UeberhoehungslinienDAO nextUeberhoehungslinienElement = getNextUeberhoehungslinienElement(nearestUeberhoehungslinienElement);
		UeberhoehungslinienDAO prevUeberhoehungslinienElement = getPreviousUeberhoehungslinienElement(nearestUeberhoehungslinienElement);
		LageskizzenWeichenDAO nearestWeiche = getNearestWeiche(position);
		List<LageskizzenGVPDAO> nearestGVPs = getNearestGVPs(position);

		QueryResult result = new QueryResult(position,
				nearestBauwerkslinienElement, nearestHoehenlinienElement,
				nearestKruemmungslinienElement,
				nearestUeberhoehungslinienElement,
				nextUeberhoehungslinienElement, prevUeberhoehungslinienElement,
				nearestWeiche, nearestGVPs);
		saveQueryResult(result);

		return result;
	}

	public void saveQueryResult(QueryResult result) {
		StringBuilder sb = new StringBuilder();
		sb.append("Projektname: ").append(projekt.getAuftragsNr()).append("\n");
		sb.append("Stationierung: ").append(result.gets0()).append("\n");
		sb.append("Gleis: ").append(getCurrentGleis().getBezeichnung())
				.append("\n");

		sb.append(result.toString());

		Writer output = null;
		try {
			String path = new File(loadedFilePath).getParent();
			String filename = projekt.getAuftragsNr() + "_" + result.gets0()
					+ ".txt";
			output = new BufferedWriter(new FileWriter(path + File.separator
					+ filename));
			output.write(sb.toString());
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				if (output != null) {
					output.close();
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}

	private UeberhoehungslinienDAO getPreviousUeberhoehungslinienElement(
			UeberhoehungslinienDAO ueberhoehungsElement) {
		UeberhoehungslinienDAO prevUeberhoehungsElement = null;

		if (ueberhoehungsElement != null) {
			// Element davor holen, falls vorhanden
			SortedSet<UeberhoehungslinienDAO> previousElements = Manager
					.getInstance().getUeberhoehungslinienElemente()
					.headSet(ueberhoehungsElement);
			if (!previousElements.isEmpty()) {
				prevUeberhoehungsElement = previousElements.last();
			}
		}
		return prevUeberhoehungsElement;
	}

	private UeberhoehungslinienDAO getNextUeberhoehungslinienElement(
			UeberhoehungslinienDAO ueberhoehungsElement) {
		UeberhoehungslinienDAO nextUeberhoehungsElement = null;

		if (ueberhoehungsElement != null) {
			// Element danach holen, falls vorhanden
			SortedSet<UeberhoehungslinienDAO> nextElements = Manager
					.getInstance().getUeberhoehungslinienElemente()
					.tailSet(ueberhoehungsElement);
			if (!nextElements.isEmpty()) {
				Iterator<UeberhoehungslinienDAO> it = nextElements.iterator();
				it.next();// das erste Element überspringen, weil es das ist,
				// womit die Menge geteilt wurde
				if (it.hasNext()) {
					nextUeberhoehungsElement = it.next();
				}
			}
		}

		return nextUeberhoehungsElement;
	}

	/**
	 * Gibt entweder das sich auf dem Punkt befindende Bauwerk zurück, oder
	 * falls nicht vorhanden das am nächsten liegende Bauwerkselement.
	 * 
	 * @param position
	 * @return
	 */
	public BauwerkslinienDAO getNearestBauwerkslinienElement(double position) {
		BauwerkslinienDAO nearestBauwerkslinienElement = null;
		double minAbstand = Double.MAX_VALUE;
		for (BauwerkslinienDAO dao : bauwerkslinienElemente) {
			double stationierung = dao.getStationierungVonInMeter();
			double endstationierung = dao.getStationierungBisInMeter();
			if ((stationierung <= position) && (endstationierung >= position)) {
				return dao;
			} else {
				double abstand = Math.min(Math.abs(position - stationierung),
						Math.abs(position - endstationierung));
				if (abstand <= minAbstand) {
					minAbstand = abstand;
					nearestBauwerkslinienElement = dao;
				}
			}
		}
		return nearestBauwerkslinienElement;
	}

	/**
	 * Gibt das Krümmungslinienelement zurück, indem sich s0 befindet
	 * 
	 * @param position
	 * @return
	 */
	public KruemmungslinienDAO getNearestKruemmungslinienElement(double position) {
		KruemmungslinienDAO nearestKruemmungslinienElement = null;
		for (KruemmungslinienDAO dao : currentGleis
				.getKruemmungslinienElemente()) {
			double stationierung = dao.getStationierungInMeter();
			double endstationierung = dao.getEndstationierungInMeter();
			if ((stationierung <= position) && (endstationierung >= position)) {
				return dao;
			}
		}
		return nearestKruemmungslinienElement;
	}

	/**
	 * Gibt das Überhohungslinienelement zurück, indem sich s0 befindet
	 * 
	 * @param position
	 * @return
	 */
	public UeberhoehungslinienDAO getNearestUeberhoehungslinienElement(
			double position) {
		UeberhoehungslinienDAO nearestUeberhoehungslinienElement = null;

		for (UeberhoehungslinienDAO dao : currentGleis
				.getUeberhoehungslinienElemente()) {
			double stationierung = dao.getStationierungInMeterUe();
			double endstationierung = dao.getEndstationierungInMeterUE();
			if ((stationierung <= position) && (endstationierung >= position)) {
				return dao;
			}
		}
		// nearestUeberhoehungslinienElement = UeberhoehungslinienDAO.get(i);
		return nearestUeberhoehungslinienElement;
	}

	/**
	 * Gibt entweder die sich auf dem Punkt befindende Weiche zurück, oder falls
	 * nicht vorhanden die am nächsten liegende Weiche.
	 * 
	 * @param position
	 * @return
	 */
	public LageskizzenWeichenDAO getNearestWeiche(double position) {
		LageskizzenWeichenDAO nearestWeiche = null;
		double minAbstand = Double.MAX_VALUE;
		for (LageskizzenWeichenDAO dao : lageskizzenWeichen) {
			double stationierung = dao.getstationWeiche();
			if (stationierung == position) {
				return dao;
			} else {
				double abstand = Math.abs(position - stationierung);
				if (abstand <= minAbstand) {
					minAbstand = abstand;
					nearestWeiche = dao;
				}
			}
		}
		return nearestWeiche;
	}

	/**
	 * Gibt entweder den sich auf dem Punkt befindende NW zurück, oder falls
	 * nicht vorhanden den am nächsten liegende NW.
	 * 
	 * @param position
	 * @return
	 */
	public HoehenlinienDAO getNearestHoehenlinienElement(double position) {
		HoehenlinienDAO nearestHoehenlinienElement = null;
		double minAbstand = Double.MAX_VALUE;
		for (HoehenlinienDAO dao : getHoehenlinienElemente()) {
			double stationierung = dao.getStationierungInMeter();
			double abstand = Math.abs(position - stationierung);
			if (abstand <= minAbstand) {
				minAbstand = abstand;
				nearestHoehenlinienElement = dao;
			}

		}
		return nearestHoehenlinienElement;
	}

	public List<LageskizzenGVPDAO> getNearestGVPs(double position) {
		List<LageskizzenGVPDAO> nearestGVPs = new ArrayList<LageskizzenGVPDAO>();
		LageskizzenGVPDAO nearestGVP = null;

		for (LageskizzenGVPDAO dao : getLageskizzenGVPs()) {
			if (dao.getstationGVPLinks() == position
					|| dao.getstationGVPRechts() == position) {
				nearestGVP = dao;
				break;
			}
		}
		if (nearestGVP != null) {
			nearestGVPs.add(nearestGVP);
			SortedSet<LageskizzenGVPDAO> nextGVPs = lageskizzenGVPs
					.tailSet(nearestGVP);
			if (!nextGVPs.isEmpty()) {
				if (nextGVPs.size() > 1) {// nur falls mehr als 1 Element
					// enthalten ist, sonst ist es eh
					// das gleiche
					Iterator<LageskizzenGVPDAO> it = nextGVPs.iterator();
					it.next();// das erste Element überspringen, weil es das
					// ist, womit die Menge geteilt wurde
					nearestGVPs.add(it.next());
				}
			}
		} else {
			LageskizzenGVPDAO dummyGVP = new LageskizzenGVPDAO(null, position,
					0, 0, null, position, 0, 0, 0, 0);
			SortedSet<LageskizzenGVPDAO> prevGVPs = lageskizzenGVPs
					.headSet(dummyGVP);
			if (!prevGVPs.isEmpty()) {
				nearestGVPs.add(prevGVPs.last());
			}
			SortedSet<LageskizzenGVPDAO> nextGVPs = lageskizzenGVPs
					.tailSet(dummyGVP);
			if (!nextGVPs.isEmpty()) {
				nearestGVPs.add(nextGVPs.first());
			}
		}
		return nearestGVPs;
	}

	public void loadXMLFile(String path) {
		this.loadedFilePath = path;
		try {
			DocumentBuilderFactory factory = DocumentBuilderFactory
					.newInstance();
			DocumentBuilder builder = factory.newDocumentBuilder();

			// XML Dokument laden
			InputStream is = new BufferedInputStream(new FileInputStream(path));
			doc = builder.parse(is);
			System.out.println(isValidDocument(doc));
			loadProjekt();

		} catch (ParserConfigurationException e) {
			e.printStackTrace();
		} catch (SAXException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	public void loadExistingProjekt(String auftragsnummer) {
		loadXMLFile(dataFolder + File.separator + auftragsnummer + ".xml");
	}

	/**
	 * Testet ob bereits Projekt mit gegebener Auftragsnummer existiert
	 * 
	 * @param auftragsnummer
	 *            die Auftragsnummer des Projektes
	 * @return TRUE wenn Projekt bereits existiert, sonst FALSE
	 */
	public boolean projektExists(String auftragsnummer) {
		return new File(dataFolder + File.separator + auftragsnummer + ".xml")
				.exists();
	}

	/**
	 * Testet ob bereits Projekt mit gegebener Auftragsnummer bereits geladen
	 * wurde
	 * 
	 * @param auftragsnummer
	 *            die Auftragsnummer des Projektes
	 * @return TRUE wenn Projekt bereits geladen, sonst FALSE
	 */
	public boolean projektLoaded(String auftragsnummer) {
		return projekt != null
				&& projekt.getAuftragsNr().equals(auftragsnummer);
	}

	private void loadProjekt() {
		// Wurzelknoten laden
		projektNode = doc.getDocumentElement();

		String auftragsnummer = ((Element) projektNode.getElementsByTagName(
				XMLTags.AUFTRAGSNUMMER).item(0)).getTextContent();
		String projektBeschreibung = ((Element) projektNode
				.getElementsByTagName(XMLTags.PROJEKTBESCHREIBUNG).item(0))
				.getTextContent();
		int gleisAnzahl = Integer.valueOf(((Element) projektNode
				.getElementsByTagName(XMLTags.GLEISANZAHL).item(0))
				.getTextContent());
		int geschwindigkeit = Integer.valueOf(((Element) projektNode
				.getElementsByTagName(XMLTags.ENTWURFSGESCHWINDIGKEIT).item(0))
				.getTextContent());
		String koordinatensystem = "";
		if (projektNode.getElementsByTagName(XMLTags.KOORDINATENSYSTEM)
				.getLength() == 1) {
			koordinatensystem = projektNode
					.getElementsByTagName(XMLTags.KOORDINATENSYSTEM).item(0)
					.getTextContent();
		}
		String hoehensystem = "";
		if (projektNode.getElementsByTagName(XMLTags.HOEHENSSYSTEM).getLength() == 1) {
			hoehensystem = projektNode
					.getElementsByTagName(XMLTags.HOEHENSSYSTEM).item(0)
					.getTextContent();
		}
		projekt = new ProjektDatenDAO(auftragsnummer, projektBeschreibung,
				gleisAnzahl, geschwindigkeit, koordinatensystem, hoehensystem);

		reset();
		// Gleise laden
		loadGleise();
		// Bauwerkslinie laden
		loadBauwerkslinie();
		// Lageskizze laden
		loadLageskizze();
	}

	private boolean isValidDocument(Document document) {
		try {
			// create a SchemaFactory capable of understanding WXS schemas
			SchemaFactory factory = SchemaFactory
					.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);

			// load a WXS schema, represented by a Schema instance
			Source schemaFile = new StreamSource(
					ClassLoader.getSystemResourceAsStream(SCHEMA_FILE));
			Schema schema = factory.newSchema(schemaFile);

			// create a Validator instance, which can be used to validate an
			// instance document
			Validator validator = schema.newValidator();

			// validate the DOM tree
			validator.validate(new DOMSource(document));
		} catch (SAXException e) {
			e.printStackTrace();
			return false;
		} catch (IOException e) {
			e.printStackTrace();
			return false;
		}
		return true;
	}

	private void reset() {
		scheduledChanges = new ArrayList<ProjektChange>();

		bauwerkslinienElemente = new TreeSet<BauwerkslinienDAO>();
		lageskizzenGVPs = new TreeSet<LageskizzenGVPDAO>();
		lageskizzenWeichen = new TreeSet<LageskizzenWeichenDAO>();
		gleisElemente = new ArrayList<GleisDAO>();

	}

	/**
	 * Änderung in eine Art Warteschlange übernehmen, welche erst in die
	 * XML-Datei übernommen werden wenn applyChanges() aufgerufen wird.
	 **/
	public void addProjektChange(ProjektChange change) {
		scheduledChanges.add(change);
	}

	/**
	 * Änderung in eine Art Warteschlange übernehmen, welche erst in die
	 * XML-Datei übernommen werden wenn applyChanges() aufgerufen wird.
	 **/
	public void addProjektChanges(List<ProjektChange> changes) {
		scheduledChanges.addAll(changes);
	}

	/**
	 * Ausstehende Änderungen in XML-Datei übernehmen.
	 */
	@SuppressWarnings("unchecked")
	public void applyChanges() {
		for (ProjektChange change : scheduledChanges) {
			if (change instanceof AddProjektElement) {
				DAO element2Add = ((AddProjektElement) change).getElement2Add();
				Collection<DAO> collection = (Collection<DAO>) getCollectionForElementType(element2Add);
				collection.add(element2Add);
			} else if (change instanceof RemoveProjektElement) {
				DAO element2Remove = ((RemoveProjektElement) change)
						.getElement2Remove();
				Collection<DAO> collection = (Collection<DAO>) getCollectionForElementType(element2Remove);
				collection.remove(element2Remove);
			} else if (change instanceof UpdateProjektElement) {
				DAO element2Remove = ((UpdateProjektElement) change)
						.getElement2Remove();
				Collection<DAO> collection2 = (Collection<DAO>) getCollectionForElementType(element2Remove);
				collection2.remove(element2Remove);

				DAO element2Add = ((UpdateProjektElement) change)
						.getElement2Add();
				Collection<DAO> collection1 = (Collection<DAO>) getCollectionForElementType(element2Add);
				collection1.add(element2Add);

			}
		}
		scheduledChanges.clear();
		write2Disk();
	}

	/**
	 * Gibt die passende Collection for DAO zurück.
	 * 
	 * @param dao
	 * @return
	 */
	private Collection<? extends DAO> getCollectionForElementType(DAO dao) {
		if (dao instanceof BauwerkslinienDAO) {
			return bauwerkslinienElemente;
		} else if (dao instanceof HoehenlinienDAO) {
			return currentGleis.getHoehenlinienElemente();
		} else if (dao instanceof UeberhoehungslinienDAO) {
			return currentGleis.getUeberhoehungslinienElemente();
		} else if (dao instanceof KruemmungslinienDAO) {
			return currentGleis.getKruemmungslinienElemente();
		} else if (dao instanceof LageskizzenGVPDAO) {
			return lageskizzenGVPs;
		} else if (dao instanceof LageskizzenWeichenDAO) {
			return lageskizzenWeichen;
		} else if (dao instanceof GleisDAO) {
			return gleisElemente;
		}
		return null;
	}

	/**
	 * Ausstehende Änderungen verwerfen.
	 */
	public void cancel() {
		scheduledChanges.clear();
	}

	public void executeQuery(int stationierung) {
		try {
			XPath xPath = XPathFactory.newInstance().newXPath();
			String expressionString = "//Stationierung/text()";
			XPathExpression expression = xPath.compile(expressionString);
			NodeList nodeList = (NodeList) expression.evaluate(doc,
					XPathConstants.NODESET);
			printNodes(nodeList);
		} catch (XPathExpressionException e) {
			e.printStackTrace();
		}
	}

	private KruemmungslinienDAO getKruemmungslinienElementFromNode(Element node) {
		String element = node.getElementsByTagName(XMLTags.ELEMENT).item(0)
				.getTextContent();
		double stationierungInMeter = Double.valueOf(node
				.getElementsByTagName(XMLTags.STATIONIERUNG).item(0)
				.getTextContent());
		double endstationierungInMeter = Double.valueOf(node
				.getElementsByTagName(XMLTags.ENDSTATIONIERUNG).item(0)
				.getTextContent());
		double radius = 0;
		if (node.getElementsByTagName(XMLTags.RADIUS).getLength() == 1) {
			radius = Double.valueOf(node.getElementsByTagName(XMLTags.RADIUS)
					.item(0).getTextContent());
		}

		int ueberhoehung = 0;
		if (node.getElementsByTagName(XMLTags.UEBERHOEHUNG).getLength() == 1) {
			ueberhoehung = Integer.valueOf(node
					.getElementsByTagName(XMLTags.UEBERHOEHUNG).item(0)
					.getTextContent());
		}

		Uebergangsbogen uebergangsbogen = Uebergangsbogen.NONE;
		if (node.getElementsByTagName(XMLTags.UEBERGANGSBOGEN_ID).getLength() == 1) {
			uebergangsbogen = Uebergangsbogen.valueOf(node
					.getElementsByTagName(XMLTags.UEBERGANGSBOGEN_ID).item(0)
					.getTextContent());
		}

		double laengeUeBogen = 0;
		if (node.getElementsByTagName(XMLTags.LAENGEUEBOEGN).getLength() == 1) {
			laengeUeBogen = Double.valueOf(node
					.getElementsByTagName(XMLTags.LAENGEUEBOEGN).item(0)
					.getTextContent());
		}

		double rp = 0;
		if (node.getElementsByTagName(XMLTags.RP).getLength() == 1) {
			rp = Double.valueOf(node.getElementsByTagName(XMLTags.RP).item(0)
					.getTextContent());
		}

		KruemmungslinienDAO dao = new KruemmungslinienDAO(element,
				stationierungInMeter, radius, ueberhoehung,
				endstationierungInMeter, rp, uebergangsbogen, laengeUeBogen);
		return dao;
	}

	private SortedSet<KruemmungslinienDAO> loadKruemmungslinienElemente(
			Element kruemmungslinienNode) {
		SortedSet<KruemmungslinienDAO> kruemmungslinienElemente = new TreeSet<KruemmungslinienDAO>();

		NodeList kruemmungslinienNodes = kruemmungslinienNode
				.getElementsByTagName(XMLTags.KRUEMMUNGSLINIEN_ELEMENT);
		KruemmungslinienDAO dao;
		for (int i = 0; i < kruemmungslinienNodes.getLength(); i++) {
			dao = getKruemmungslinienElementFromNode((Element) kruemmungslinienNodes
					.item(i));
			kruemmungslinienElemente.add(dao);
		}
		return kruemmungslinienElemente;
	}

	private Element createKruemmungslinienElementNode(KruemmungslinienDAO dao) {
		// Knoten für ein KruemmungslinenElement anlegen
		Element kruemmungsLinie = doc
				.createElement(XMLTags.KRUEMMUNGSLINIEN_ELEMENT);

		// Knoten für Element anlegen
		Element element = doc.createElement(XMLTags.ELEMENT);
		element.appendChild(doc.createTextNode(String.valueOf(dao.getElement())));
		kruemmungsLinie.appendChild(element);
		// Knoten für Stationierung anlegen
		Element stationierung = doc.createElement(XMLTags.STATIONIERUNG);
		stationierung.appendChild(doc.createTextNode(String.valueOf(dao
				.getStationierungInMeter())));
		kruemmungsLinie.appendChild(stationierung);
		// Knoten für Endstationierung anlegen
		Element endstationierung = doc.createElement(XMLTags.ENDSTATIONIERUNG);
		endstationierung.appendChild(doc.createTextNode(String.valueOf(dao
				.getEndstationierungInMeter())));
		kruemmungsLinie.appendChild(endstationierung);
		// Knoten für Radius anlegen
		if (dao.getRadius() != 0) {
			Element radius = doc.createElement(XMLTags.RADIUS);
			radius.appendChild(doc.createTextNode(String.valueOf(dao
					.getRadius())));
			kruemmungsLinie.appendChild(radius);
		}
		// Knoten für Überhöhung anlegen
		if (dao.getUeberhoehung() != 0) {
			Element ueberhoehung = doc.createElement(XMLTags.UEBERHOEHUNG);
			ueberhoehung.appendChild(doc.createTextNode(String.valueOf(dao
					.getUeberhoehung())));
			kruemmungsLinie.appendChild(ueberhoehung);
		}
		// Knoten für Übergangsbogen-ID anlegen
		if (dao.getUebergangsbogen() != Uebergangsbogen.NONE) {
			Element uebergangsbogen = doc
					.createElement(XMLTags.UEBERGANGSBOGEN_ID);
			uebergangsbogen.appendChild(doc.createTextNode(String.valueOf(dao
					.getUebergangsbogen())));
			kruemmungsLinie.appendChild(uebergangsbogen);
		}
		// Knoten für LaengeUeBogen anlegen
		if (dao.getLaengeUeBogen() != 0) {
			Element laengeUeBogen = doc.createElement(XMLTags.LAENGEUEBOEGN);
			laengeUeBogen.appendChild(doc.createTextNode(String.valueOf(dao
					.getLaengeUeBogen())));
			kruemmungsLinie.appendChild(laengeUeBogen);
		}
		// Knoten für RP anlegen
		if (dao.getRp() != 0) {
			Element rp = doc.createElement(XMLTags.RP);
			rp.appendChild(doc.createTextNode(String.valueOf(dao.getRp())));
			kruemmungsLinie.appendChild(rp);
		}

		return kruemmungsLinie;
	}

	public SortedSet<KruemmungslinienDAO> getKruemmungslinienElemente() {
		return currentGleis.getKruemmungslinienElemente();
	}

	private UeberhoehungslinienDAO getUeberhoehungslinienElementFromNode(
			Element node) {
		double stationierungInMeterUE = Double.valueOf(node
				.getElementsByTagName(XMLTags.STATIONIERUNG).item(0)
				.getTextContent());
		double endstationierungInMeterUE = Double.valueOf(node
				.getElementsByTagName(XMLTags.ENDSTATIONIERUNG).item(0)
				.getTextContent());

		int ueberhoehungInMM = 0;
		if (node.getElementsByTagName(XMLTags.UEBERHOEHUNG).getLength() == 1) {
			ueberhoehungInMM = Integer.valueOf(node
					.getElementsByTagName(XMLTags.UEBERHOEHUNG).item(0)
					.getTextContent());
		}

		double laengeRampe = 0;
		if (node.getElementsByTagName(XMLTags.LAENGERAMPE).getLength() == 1) {
			laengeRampe = Double.valueOf(node
					.getElementsByTagName(XMLTags.LAENGERAMPE).item(0)
					.getTextContent());
		}

		Ueberhoehungsrampe ueberhoehungsrampe = Ueberhoehungsrampe.NONE;
		if (node.getElementsByTagName(XMLTags.RAMPEN_ID).getLength() == 1) {
			ueberhoehungsrampe = Ueberhoehungsrampe.valueOf(node
					.getElementsByTagName(XMLTags.RAMPEN_ID).item(0)
					.getTextContent());
		}

		UeberhoehungslinienDAO dao = new UeberhoehungslinienDAO(
				stationierungInMeterUE, ueberhoehungInMM,
				endstationierungInMeterUE, ueberhoehungsrampe, laengeRampe);
		return dao;
	}

	private SortedSet<UeberhoehungslinienDAO> loadUeberhoehungslinienElemente(
			Element ueberhoehungslinienNode) {
		SortedSet<UeberhoehungslinienDAO> ueberhoehungslinienElemente = new TreeSet<UeberhoehungslinienDAO>();

		NodeList ueberhoehungslinienNodes = ueberhoehungslinienNode
				.getElementsByTagName(XMLTags.UEBERHOEHUNGSLINIEN_ELEMENT);
		UeberhoehungslinienDAO dao;
		for (int i = 0; i < ueberhoehungslinienNodes.getLength(); i++) {
			dao = getUeberhoehungslinienElementFromNode((Element) ueberhoehungslinienNodes
					.item(i));
			ueberhoehungslinienElemente.add(dao);
		}

		return ueberhoehungslinienElemente;
	}

	private Element createUeberhoehunglinienElementNode(
			UeberhoehungslinienDAO dao) {
		// Knoten für ein ÜberhöhungslinienElement anlegen
		Element ueberhoehungslinie = doc
				.createElement(XMLTags.UEBERHOEHUNGSLINIEN_ELEMENT);

		// Knoten für Stationierung anlegen
		Element stationierungUE = doc.createElement(XMLTags.STATIONIERUNG);
		stationierungUE.appendChild(doc.createTextNode(String.valueOf(dao
				.getStationierungInMeterUe())));
		ueberhoehungslinie.appendChild(stationierungUE);
		// Knoten für Endstationierung anlegen
		Element endstationierungInMeterUE = doc
				.createElement(XMLTags.ENDSTATIONIERUNG);
		endstationierungInMeterUE.appendChild(doc.createTextNode(String
				.valueOf(dao.getEndstationierungInMeterUE())));
		ueberhoehungslinie.appendChild(endstationierungInMeterUE);
		// Knoten für Überhöhung anlegen
		if (dao.getUeberhoehungInMM() != 0) {
			Element ueberhoehung = doc.createElement(XMLTags.UEBERHOEHUNG);
			ueberhoehung.appendChild(doc.createTextNode(String.valueOf(dao
					.getUeberhoehungInMM())));
			ueberhoehungslinie.appendChild(ueberhoehung);
		}
		// Knoten für Überhöhungsrampe anlegen
		if (dao.getUeberhoehungsrampe() != Ueberhoehungsrampe.NONE) {
			Element ueberhoehungsrampe = doc.createElement(XMLTags.RAMPEN_ID);
			ueberhoehungsrampe.appendChild(doc.createTextNode(String
					.valueOf(dao.getUeberhoehungsrampe())));
			ueberhoehungslinie.appendChild(ueberhoehungsrampe);
		}
		// Knoten für Rampenlänge anlegen
		if (dao.getLaengeRampe() != 0) {
			Element rampenlaenge = doc.createElement(XMLTags.LAENGERAMPE);
			rampenlaenge.appendChild(doc.createTextNode(String.valueOf(dao
					.getLaengeRampe())));
			ueberhoehungslinie.appendChild(rampenlaenge);
		}

		return ueberhoehungslinie;
	}

	public SortedSet<UeberhoehungslinienDAO> getUeberhoehungslinienElemente() {
		return currentGleis.getUeberhoehungslinienElemente();
	}

	private HoehenlinienDAO getHoehenlinienElementFromNode(Element node) {
		double neigungAn = Double.valueOf(node
				.getElementsByTagName(XMLTags.ANKOMMENDE_NEIGUNG).item(0)
				.getTextContent());
		double laengeAn = Double.valueOf(node
				.getElementsByTagName(XMLTags.ANKOMMENDE_LAENGE).item(0)
				.getTextContent());
		double hoehe = Double.valueOf(node.getElementsByTagName(XMLTags.HOEHE)
				.item(0).getTextContent());
		double stationierungInMeter = Double.valueOf(node
				.getElementsByTagName(XMLTags.STATIONIERUNG).item(0)
				.getTextContent());
		int ra = 0;
		if (node.getElementsByTagName(XMLTags.RA).getLength() == 1) {
			ra = Integer.valueOf(node.getElementsByTagName(XMLTags.RA).item(0)
					.getTextContent());
		}
		double lt = 0;
		if (node.getElementsByTagName(XMLTags.LT).getLength() == 1) {
			lt = Double.valueOf(node.getElementsByTagName(XMLTags.LT).item(0)
					.getTextContent());
		}
		double a = 0;
		if (node.getElementsByTagName(XMLTags.A).getLength() == 1) {
			a = Double.valueOf(node.getElementsByTagName(XMLTags.A).item(0)
					.getTextContent());
		}
		double neigungAb = Double.valueOf(node
				.getElementsByTagName(XMLTags.ABGEHENDE_NEIGUNG).item(0)
				.getTextContent());
		double laengeAb = Double.valueOf(node
				.getElementsByTagName(XMLTags.ABGEHENDE_LAENGE).item(0)
				.getTextContent());

		HoehenlinienDAO dao = new HoehenlinienDAO(neigungAn, laengeAn, hoehe,
				stationierungInMeter, ra, lt, a, neigungAb, laengeAb);

		return dao;
	}

	private SortedSet<HoehenlinienDAO> loadHoehenlinienElemente(
			Element hoehenlinienNode) {
		SortedSet<HoehenlinienDAO> hoehenlinienElemente = new TreeSet<HoehenlinienDAO>();

		NodeList hoehenlinienNodes = hoehenlinienNode
				.getElementsByTagName(XMLTags.HOEHENLINIEN_ELEMENT);
		HoehenlinienDAO dao;
		for (int i = 0; i < hoehenlinienNodes.getLength(); i++) {
			dao = getHoehenlinienElementFromNode((Element) hoehenlinienNodes
					.item(i));
			hoehenlinienElemente.add(dao);
		}
		return hoehenlinienElemente;
	}

	private Element createHoehenlinienElementNode(HoehenlinienDAO dao) {
		// Knoten für ein HöhenlinienElement anlegen
		Element hoehenlinie = doc.createElement(XMLTags.HOEHENLINIEN_ELEMENT);

		// Knoten für ankommende Neigung anlegen
		Element neigungAn = doc.createElement(XMLTags.ANKOMMENDE_NEIGUNG);
		neigungAn.appendChild(doc.createTextNode(String.valueOf(dao
				.getNeigungAn())));
		hoehenlinie.appendChild(neigungAn);
		// Knoten für ankommende Länge anlegen
		Element laengeAn = doc.createElement(XMLTags.ANKOMMENDE_LAENGE);
		laengeAn.appendChild(doc.createTextNode(String.valueOf(dao
				.getLaengeAn())));
		hoehenlinie.appendChild(laengeAn);
		// Knoten für Stationierung anlegen
		Element stationierung = doc.createElement(XMLTags.STATIONIERUNG);
		stationierung.appendChild(doc.createTextNode(String.valueOf(dao
				.getStationierungInMeter())));
		hoehenlinie.appendChild(stationierung);
		// Knoten für Höhe anlegen
		Element hoehe = doc.createElement(XMLTags.HOEHE);
		hoehe.appendChild(doc.createTextNode(String.valueOf(dao.gethoehe())));
		hoehenlinie.appendChild(hoehe);
		// Knoten für Ra anlegen
		if (dao.getRa() != 0) {
			Element ra = doc.createElement(XMLTags.RA);
			ra.appendChild(doc.createTextNode(String.valueOf(dao.getRa())));
			hoehenlinie.appendChild(ra);
		}
		// Knoten für Lt anlegen
		if (dao.getLt() != 0) {
			Element lt = doc.createElement(XMLTags.LT);
			lt.appendChild(doc.createTextNode(String.valueOf(dao.getLt())));
			hoehenlinie.appendChild(lt);
		}
		// Knoten für A anlegen
		if (dao.getA() != 0) {
			Element a = doc.createElement(XMLTags.A);
			a.appendChild(doc.createTextNode(String.valueOf(dao.getA())));
			hoehenlinie.appendChild(a);
		}
		// Knoten für abgehende Neigung anlegen
		Element neigungAb = doc.createElement(XMLTags.ABGEHENDE_NEIGUNG);
		neigungAb.appendChild(doc.createTextNode(String.valueOf(dao
				.getNeigungAb())));
		hoehenlinie.appendChild(neigungAb);
		// Knoten für abgehende Länge anlegen
		Element laengeAb = doc.createElement(XMLTags.ABGEHENDE_LAENGE);
		laengeAb.appendChild(doc.createTextNode(String.valueOf(dao
				.getLaengeAb())));
		hoehenlinie.appendChild(laengeAb);

		return hoehenlinie;
	}

	public SortedSet<HoehenlinienDAO> getHoehenlinienElemente() {
		return currentGleis.getHoehenlinienElemente();
	}

	private LageskizzenGVPDAO getLageskizzenGVPFromNode(Element node) {
		String punktNrGVPLinks = "";
		if (node.getElementsByTagName(XMLTags.PUNKTNUMMERGVPLINKS).getLength() == 1) {
			punktNrGVPLinks = node
					.getElementsByTagName(XMLTags.PUNKTNUMMERGVPLINKS).item(0)
					.getTextContent();
		}
		String punktNrGVPRechts = "";
		if (node.getElementsByTagName(XMLTags.PUNKTNUMMERGVPRECHTS).getLength() == 1) {
			punktNrGVPRechts = node
					.getElementsByTagName(XMLTags.PUNKTNUMMERGVPRECHTS).item(0)
					.getTextContent();
		}
		double stationGVPLinks = 0;
		if (node.getElementsByTagName(XMLTags.STATIONLINKS).getLength() == 1) {
			stationGVPLinks = Double.valueOf(node
					.getElementsByTagName(XMLTags.STATIONLINKS).item(0)
					.getTextContent());
		}
		double stationGVPRechts = 0;
		if (node.getElementsByTagName(XMLTags.STATIONRECHTS).getLength() == 1) {
			stationGVPRechts = Double.valueOf(node
					.getElementsByTagName(XMLTags.STATIONRECHTS).item(0)
					.getTextContent());
		}
		int hoehenmaßGVPLinks = 0;
		if (node.getElementsByTagName(XMLTags.HOEHENMASSLINKS).getLength() == 1) {
			hoehenmaßGVPLinks = Integer.valueOf(node
					.getElementsByTagName(XMLTags.HOEHENMASSLINKS).item(0)
					.getTextContent());
		}
		int hoehenmaßGVPRechts = 0;
		if (node.getElementsByTagName(XMLTags.HOEHENMASSRECHTS).getLength() == 1) {
			hoehenmaßGVPRechts = Integer.valueOf(node
					.getElementsByTagName(XMLTags.HOEHENMASSRECHTS).item(0)
					.getTextContent());
		}
		double querGVPLinks = 0;
		if (node.getElementsByTagName(XMLTags.QUERGVPLINKS).getLength() == 1) {
			querGVPLinks = Double.valueOf(node
					.getElementsByTagName(XMLTags.QUERGVPLINKS).item(0)
					.getTextContent());
		}
		double querGleisLinks = 0;
		if (node.getElementsByTagName(XMLTags.QUERLINKESGLEIS).getLength() == 1) {
			querGleisLinks = Double.valueOf(node
					.getElementsByTagName(XMLTags.QUERLINKESGLEIS).item(0)
					.getTextContent());
		}
		double querGleisRechts = 0;
		if (node.getElementsByTagName(XMLTags.QUERRECHTESGLEIS).getLength() == 1) {
			querGleisRechts = Double.valueOf(node
					.getElementsByTagName(XMLTags.QUERRECHTESGLEIS).item(0)
					.getTextContent());
		}
		double gleisabstand = 0;
		if (node.getElementsByTagName(XMLTags.GLEISABSTAND).getLength() == 1) {
			gleisabstand = Double.valueOf(node
					.getElementsByTagName(XMLTags.GLEISABSTAND).item(0)
					.getTextContent());
		}

		LageskizzenGVPDAO dao = new LageskizzenGVPDAO(punktNrGVPLinks,
				stationGVPLinks, hoehenmaßGVPLinks, querGVPLinks,
				punktNrGVPRechts, stationGVPRechts, hoehenmaßGVPRechts,
				querGleisLinks, querGleisRechts, gleisabstand);
		return dao;
	}

	private LageskizzenWeichenDAO getLageskizzenWeicheFromNode(Element node) {
		double stationWeiche = Double.valueOf(node
				.getElementsByTagName(XMLTags.STATIONWEICHE).item(0)
				.getTextContent());
		String nummerWeiche = "";
		if (node.getElementsByTagName(XMLTags.WEICHENNR).getLength() == 1) {
			nummerWeiche = node.getElementsByTagName(XMLTags.WEICHENNR).item(0)
					.getTextContent();
		}
		String bezWeiche = node.getElementsByTagName(XMLTags.WEICHENBEZ)
				.item(0).getTextContent();

		LageskizzenWeichenDAO dao = new LageskizzenWeichenDAO(stationWeiche,
				nummerWeiche, bezWeiche);
		return dao;
	}

	public void loadLageskizze() {
		lageskizzenNode = (Element) doc
				.getElementsByTagName(XMLTags.LAGESKIZZE).item(0);

		// GVPs laden
		NodeList gvpNodes = lageskizzenNode.getElementsByTagName(XMLTags.GVP);
		LageskizzenGVPDAO gvpDAO;
		for (int i = 0; i < gvpNodes.getLength(); i++) {
			gvpDAO = getLageskizzenGVPFromNode((Element) gvpNodes.item(i));
			lageskizzenGVPs.add(gvpDAO);

		}

		// Weichen laden
		NodeList weichenNodes = lageskizzenNode
				.getElementsByTagName(XMLTags.WEICHE);
		LageskizzenWeichenDAO weichenDAO;
		for (int i = 0; i < weichenNodes.getLength(); i++) {
			weichenDAO = getLageskizzenWeicheFromNode((Element) weichenNodes
					.item(i));
			lageskizzenWeichen.add(weichenDAO);
		}

	}

	public SortedSet<LageskizzenGVPDAO> getLageskizzenGVPs() {
		return lageskizzenGVPs;
	}

	public SortedSet<LageskizzenWeichenDAO> getLageskizzenWeichen() {
		return lageskizzenWeichen;
	}

	private Element createLageskizzenGVPNode(LageskizzenGVPDAO dao) {
		// Knoten für eine LageskizzenGVP anlegen
		Element gvp = doc.createElement(XMLTags.GVP);

		// Knoten für Punktnummer GVP links anlegen
		if (!dao.getpunktNrGVPLinks().equals("")) {
			Element punktNrGVPLinks = doc
					.createElement(XMLTags.PUNKTNUMMERGVPLINKS);
			punktNrGVPLinks.appendChild(doc.createTextNode(dao
					.getpunktNrGVPLinks()));
			gvp.appendChild(punktNrGVPLinks);
		}
		// Knoten für Station GVP links anlegen
		if (dao.getstationGVPLinks() != 0) {
			Element stationGVPLinks = doc.createElement(XMLTags.STATIONLINKS);
			stationGVPLinks.appendChild(doc.createTextNode(String.valueOf(dao
					.getstationGVPLinks())));
			gvp.appendChild(stationGVPLinks);
		}
		// Knoten für Höhenmaß GVP links anlegen
		if (dao.gethoehenmaßGVPLinks() != 0) {
			Element hoehenmaßGVPLinks = doc
					.createElement(XMLTags.HOEHENMASSLINKS);
			hoehenmaßGVPLinks.appendChild(doc.createTextNode(String.valueOf(dao
					.gethoehenmaßGVPLinks())));
			gvp.appendChild(hoehenmaßGVPLinks);
		}
		// Knoten für Punktnummer GVP rechts anlegen
		if (!dao.getpunktNrGVPRechts().equals("")) {
			Element punktNrGVPRechts = doc
					.createElement(XMLTags.PUNKTNUMMERGVPRECHTS);
			punktNrGVPRechts.appendChild(doc.createTextNode(dao
					.getpunktNrGVPRechts()));
			gvp.appendChild(punktNrGVPRechts);
		}
		// Knoten für Station GVP rechts anlegen
		if (dao.getstationGVPRechts() != 0) {
			Element stationGVPRechts = doc.createElement(XMLTags.STATIONRECHTS);
			stationGVPRechts.appendChild(doc.createTextNode(String.valueOf(dao
					.getstationGVPRechts())));
			gvp.appendChild(stationGVPRechts);
		}
		// Knoten für Höhenmaß GVP rechts anlegen
		if (dao.gethoehenmaßGVPRechts() != 0) {
			Element hoehenmaßGVPRechts = doc
					.createElement(XMLTags.HOEHENMASSRECHTS);
			hoehenmaßGVPRechts.appendChild(doc.createTextNode(String
					.valueOf(dao.gethoehenmaßGVPRechts())));
			gvp.appendChild(hoehenmaßGVPRechts);
		}
		// Knoten für Quer GVP links anlegen
		if (dao.getquerGVPLinks() != 0) {
			Element querGVPLinks = doc.createElement(XMLTags.QUERGVPLINKS);
			querGVPLinks.appendChild(doc.createTextNode(String.valueOf(dao
					.getquerGVPLinks())));
			gvp.appendChild(querGVPLinks);
		}
		// Knoten für Quermaß linkes Gleis
		if (dao.getquerGleisLinks() != 0) {
			Element querGleisLinks = doc.createElement(XMLTags.QUERLINKESGLEIS);
			querGleisLinks.appendChild(doc.createTextNode(String.valueOf(dao
					.getquerGleisLinks())));
			gvp.appendChild(querGleisLinks);
		}
		// Knoten für Quermaß rechtes Gleis
		if (dao.getquerGleisRechts() != 0) {
			Element querGleisRechts = doc
					.createElement(XMLTags.QUERRECHTESGLEIS);
			querGleisRechts.appendChild(doc.createTextNode(String.valueOf(dao
					.getquerGleisRechts())));
			gvp.appendChild(querGleisRechts);
		}
		// Knoten für Gleisabstand
		if (dao.getgleisabstand() != 0) {
			Element gleisabstand = doc.createElement(XMLTags.GLEISABSTAND);
			gleisabstand.appendChild(doc.createTextNode(String.valueOf(dao
					.getgleisabstand())));
			gvp.appendChild(gleisabstand);
		}

		return gvp;
	}

	private Element createLageskizzenWeichenNode(LageskizzenWeichenDAO dao) {
		// Knoten für eine LageskizzenWeiche anlegen
		Element weiche = doc.createElement(XMLTags.WEICHE);

		// Knoten für Station Weiche anlegen
		Element stationWeiche = doc.createElement(XMLTags.STATIONWEICHE);
		stationWeiche.appendChild(doc.createTextNode(String.valueOf(dao
				.getstationWeiche())));
		weiche.appendChild(stationWeiche);
		// Knoten für Weichennummer anlegen
		if (!dao.getnummerWeiche().equals("")) {
			Element nummerWeiche = doc.createElement(XMLTags.WEICHENNR);
			nummerWeiche.appendChild(doc.createTextNode(dao.getnummerWeiche()));
			weiche.appendChild(nummerWeiche);
		}
		// Knoten für Weichenbezeichnung anlegen
		Element bezWeiche = doc.createElement(XMLTags.WEICHENBEZ);
		bezWeiche.appendChild(doc.createTextNode(dao.getbezWeiche()));
		weiche.appendChild(bezWeiche);

		return weiche;
	}

	private BauwerkslinienDAO getBauwerkslinienElementFromNode(Element node) {

		String bauwerk = node.getElementsByTagName(XMLTags.BAUWERK).item(0)
				.getTextContent();
		double stationierung = Double.valueOf(node
				.getElementsByTagName(XMLTags.STATIONIERUNG).item(0)
				.getTextContent());

		double endstationierung = stationierung;
		if (node.getElementsByTagName(XMLTags.ENDSTATIONIERUNG).getLength() == 1) {
			endstationierung = Double.valueOf(node
					.getElementsByTagName(XMLTags.ENDSTATIONIERUNG).item(0)
					.getTextContent());
		}

		double hoehe = 0;
		if (node.getElementsByTagName(XMLTags.HOEHE).getLength() == 1) {
			hoehe = Double.valueOf(node.getElementsByTagName(XMLTags.HOEHE)
					.item(0).getTextContent());
		}

		String besonderheiten = "";
		if (node.getElementsByTagName(XMLTags.BESONDERHEITEN).getLength() == 1) {
			besonderheiten = node.getElementsByTagName(XMLTags.BESONDERHEITEN)
					.item(0).getTextContent();
		}

		BauwerkslinienDAO dao = new BauwerkslinienDAO(bauwerk, stationierung,
				endstationierung, hoehe, besonderheiten);

		return dao;
	}

	private void loadBauwerkslinie() {
		bauwerkslinienNode = (Element) doc.getElementsByTagName(
				XMLTags.BAUWERKSLINIE).item(0);

		NodeList bauwerkslinienNodes = bauwerkslinienNode
				.getElementsByTagName(XMLTags.BAUWERKSLINIEN_ELEMENT);
		BauwerkslinienDAO dao;
		for (int i = 0; i < bauwerkslinienNodes.getLength(); i++) {
			dao = getBauwerkslinienElementFromNode((Element) bauwerkslinienNodes
					.item(i));
			bauwerkslinienElemente.add(dao);
		}
	}

	public SortedSet<BauwerkslinienDAO> getBauwerkslinienElemente() {
		return bauwerkslinienElemente;
	}

	private Element createBauwerkslinienElementNode(BauwerkslinienDAO dao) {
		// Knoten für eine Bauwerkslinie anlegen
		Element bauwerkslinienElementNode = doc
				.createElement(XMLTags.BAUWERKSLINIEN_ELEMENT);

		// Knoten für Bauwerk anlegen
		Element bauwerk = doc.createElement(XMLTags.BAUWERK);
		bauwerk.appendChild(doc.createTextNode(dao.getBauwerk()));
		bauwerkslinienElementNode.appendChild(bauwerk);
		// Knoten für Stationierung anlegen
		Element stationierung = doc.createElement(XMLTags.STATIONIERUNG);
		stationierung.appendChild(doc.createTextNode(String.valueOf(dao
				.getStationierungVonInMeter())));
		bauwerkslinienElementNode.appendChild(stationierung);
		// Knoten für Endstationierung anlegen
		if (dao.getStationierungBisInMeter() != dao
				.getStationierungVonInMeter()) {
			Element endstationierung = doc
					.createElement(XMLTags.ENDSTATIONIERUNG);
			endstationierung.appendChild(doc.createTextNode(String.valueOf(dao
					.getStationierungBisInMeter())));
			bauwerkslinienElementNode.appendChild(endstationierung);
		}
		// Knoten für Hoehe anlegen
		if (dao.getHoeheInMeter() != 0) {
			Element hoehe = doc.createElement(XMLTags.HOEHE);
			hoehe.appendChild(doc.createTextNode(String.valueOf(dao
					.getHoeheInMeter())));
			bauwerkslinienElementNode.appendChild(hoehe);
		}
		// Knoten für Besonderheiten anlegen
		if (!dao.getBesonderheiten().equals("")) {
			Element besonderheiten = doc.createElement(XMLTags.BESONDERHEITEN);
			besonderheiten.appendChild(doc.createTextNode(dao
					.getBesonderheiten()));
			bauwerkslinienElementNode.appendChild(besonderheiten);
		}

		return bauwerkslinienElementNode;
	}

	private Element createProjektNode(ProjektDatenDAO dao) {
		Element projektNode = doc.createElement("Projekt");

		// Knoten für AuftragsNummer erstellen
		Element auftragsNrNode = doc.createElement("Auftragsnummer");
		auftragsNrNode.appendChild(doc.createTextNode(dao.getAuftragsNr()));
		projektNode.appendChild(auftragsNrNode);
		// Knoten für Projektbeschreibung erstellen
		Element projektBeschreibungsNode = doc
				.createElement("Projektbeschreibung");
		projektBeschreibungsNode.appendChild(doc.createTextNode(dao
				.getProjektBeschreibung()));
		projektNode.appendChild(projektBeschreibungsNode);
		// Knoten für Anzahl der Gleise erstellen
		Element gleisAnzahlNode = doc.createElement("Gleisanzahl");
		gleisAnzahlNode.appendChild(doc.createTextNode(String.valueOf(dao
				.getGleisAnzahl())));
		projektNode.appendChild(gleisAnzahlNode);
		// Knoten für Anzahl der Gleise erstellen
		Element geschwindigkeitNode = doc
				.createElement("Entwurfsgeschwindigkeit");
		geschwindigkeitNode.appendChild(doc.createTextNode(String.valueOf(dao
				.getGeschwindigkeit())));
		projektNode.appendChild(geschwindigkeitNode);
		// Knoten für Koordinatensystem erstellen
		if (!dao.getKoordinatensystem().equals("")) {
			Element koordinatensystemNode = doc
					.createElement("Koordinatensystem");
			koordinatensystemNode.appendChild(doc.createTextNode(dao
					.getKoordinatensystem()));
			projektNode.appendChild(koordinatensystemNode);
		}
		// Knoten für Hoehensystem erstellen
		if (!dao.getHoehensystem().equals("")) {
			Element hoehensystemNode = doc.createElement("Hoehensystem");
			hoehensystemNode.appendChild(doc.createTextNode(dao
					.getHoehensystem()));
			projektNode.appendChild(hoehensystemNode);
		}

		// Knoten für GleisElemente erstellen
		gleisNode = doc.createElement("Gleise");
		for (GleisDAO gleisElement : gleisElemente) {
			gleisNode.appendChild(createGleisElementNode(gleisElement));
		}
		projektNode.appendChild(gleisNode);

		// Knoten für BauwerkslinienElemente erstellen
		bauwerkslinienNode = doc.createElement("Bauwerkslinie");
		for (BauwerkslinienDAO bauwerkslinienElement : bauwerkslinienElemente) {
			bauwerkslinienNode
					.appendChild(createBauwerkslinienElementNode(bauwerkslinienElement));
		}
		projektNode.appendChild(bauwerkslinienNode);

		// Knoten für LageskizzenElemente erstellen
		lageskizzenNode = doc.createElement("Lageskizze");
		Element gvpsNode = doc.createElement("GVPs");
		lageskizzenNode.appendChild(gvpsNode);
		for (LageskizzenGVPDAO gvp : lageskizzenGVPs) {
			gvpsNode.appendChild(createLageskizzenGVPNode(gvp));
		}
		Element weichenNode = doc.createElement("Weichen");
		lageskizzenNode.appendChild(weichenNode);
		for (LageskizzenWeichenDAO weiche : lageskizzenWeichen) {
			weichenNode.appendChild(createLageskizzenWeichenNode(weiche));
		}
		projektNode.appendChild(lageskizzenNode);

		return projektNode;
	}

	private Document buildDocument() {
		DocumentBuilder builder = null;
		try {
			DocumentBuilderFactory factory = DocumentBuilderFactory
					.newInstance();
			builder = factory.newDocumentBuilder();
		} catch (ParserConfigurationException e) {
			e.printStackTrace();
		}
		doc = builder.newDocument();
		doc.appendChild(createProjektNode(projekt));

		return doc;
	}

	public void loadGleise() {
		gleisNode = (Element) projektNode.getElementsByTagName("Gleise")
				.item(0);

		NodeList gleisNodes = gleisNode.getElementsByTagName("Gleis");
		Element gleis;
		GleisDAO dao;
		for (int i = 0; i < gleisNodes.getLength(); i++) {
			gleis = (Element) gleisNodes.item(i);

			int gleisID = Integer.valueOf(gleis.getAttribute("id"));
			String bezeichnung = ((Element) gleis.getElementsByTagName(
					"Bezeichnung").item(0)).getTextContent();
			double anfangsStation = Double.valueOf(((Element) gleis
					.getElementsByTagName("Anfangsstation").item(0))
					.getTextContent());
			double abstandKmLinie = 0;
			if (gleis.getElementsByTagName("Abstand_km-Linie").getLength() == 1) {
				abstandKmLinie = Double.valueOf(gleis
						.getElementsByTagName("Abstand_km-Linie").item(0)
						.getTextContent());
			}

			Element kruemmungslinienNode = (Element) gleis
					.getElementsByTagName("Krümmungslinie").item(0);
			SortedSet<KruemmungslinienDAO> kruemmungslinienElemente = loadKruemmungslinienElemente(kruemmungslinienNode);

			Element ueberhoehungslinienNode = (Element) gleis
					.getElementsByTagName("Überhöhungslinie").item(0);
			SortedSet<UeberhoehungslinienDAO> ueberheohungslinienElemente = loadUeberhoehungslinienElemente(ueberhoehungslinienNode);

			Element hoehenlinienNode = (Element) gleis.getElementsByTagName(
					"Höhenlinie").item(0);
			SortedSet<HoehenlinienDAO> hoehenlinienElemente = loadHoehenlinienElemente(hoehenlinienNode);

			dao = new GleisDAO(gleisID, bezeichnung, anfangsStation,
					abstandKmLinie, kruemmungslinienElemente,
					ueberheohungslinienElemente, hoehenlinienElemente);

			gleisElemente.add(dao);
		}
	}

	private Element createGleisElementNode(GleisDAO dao) {
		// Knoten für ein GleisElement anlegen
		Element gleisElement = doc.createElement("Gleis");

		// Attribut für ID anlegen
		Attr id = doc.createAttribute("id");
		id.setValue(String.valueOf(dao.getGleisID()));
		gleisElement.setAttributeNode(id);
		// Knoten für Bezeichnung anlegen
		Element bezeichnung = doc.createElement("Bezeichnung");
		bezeichnung.appendChild(doc.createTextNode(String.valueOf(dao
				.getBezeichnung())));
		gleisElement.appendChild(bezeichnung);
		// Knoten für Anfangsstation anlegen
		Element anfangsStation = doc.createElement("Anfangsstation");
		anfangsStation.appendChild(doc.createTextNode(String.valueOf(dao
				.getAnfangsStation())));
		gleisElement.appendChild(anfangsStation);
		// Knoten für Abstand_km-Linie anlegen
		Element abstandKmLinie = doc.createElement("Abstand_km-Linie");
		abstandKmLinie.appendChild(doc.createTextNode(String.valueOf(dao
				.getAbstandKmLinie())));
		gleisElement.appendChild(abstandKmLinie);

		// Höhenlinie hinzufügen
		Element hoehenlinie = doc.createElement("Höhenlinie");
		for (HoehenlinienDAO hoehenlinienElement : dao
				.getHoehenlinienElemente()) {
			hoehenlinie
					.appendChild(createHoehenlinienElementNode(hoehenlinienElement));
		}
		gleisElement.appendChild(hoehenlinie);

		// Krümmungslinie hinzufügen
		Element kruemmungslinie = doc.createElement("Krümmungslinie");
		for (KruemmungslinienDAO kruemmungslinienElement : dao
				.getKruemmungslinienElemente()) {
			kruemmungslinie
					.appendChild(createKruemmungslinienElementNode(kruemmungslinienElement));
		}
		gleisElement.appendChild(kruemmungslinie);

		// Überhöhungslinie hinzufügen
		Element ueberhoehungslinie = doc.createElement("Überhöhungslinie");
		for (UeberhoehungslinienDAO ueberhoehungslinienElement : dao
				.getUeberhoehungslinienElemente()) {
			ueberhoehungslinie
					.appendChild(createUeberhoehunglinienElementNode(ueberhoehungslinienElement));
		}
		gleisElement.appendChild(ueberhoehungslinie);

		return gleisElement;
	}

	public List<GleisDAO> getGleisElemente() {
		return gleisElemente;
	}

	private void printNodes(NodeList nodeList) {
		for (int i = 0; i < nodeList.getLength(); i++) {
			System.out.println(nodeList.item(i));
		}
	}

	public void setProjekt(ProjektDatenDAO projekt) {
		this.projekt = projekt;
	}

	public void setCurrentGleis(GleisDAO currentGleis) {
		this.currentGleis = currentGleis;
	}

	public GleisDAO getCurrentGleis() {
		return currentGleis;
	}

	public ProjektDatenDAO getProjekt() {
		return projekt;
	}

	public static void main(String[] args) {
		Manager.getInstance().loadExistingProjekt("test");
	}
}
